/*
 * CLexAnalyser7.cpp
 *
 *  Created on: Oct 21, 2011
 *      Author: Wincloud Bear
 */

#include "CLexAnalyser7.h"

#include "ctokenanalyser.h"

#include<stdlib.h>
#include<string.h>
#include<stdio.h>
CTokenAnalyser::CTokenAnalyser():
    _idCounter(0),
    _numCounter(0),
    _reverseWordCounter(0)
{

}


/*去除后面的空格符*/
void CTokenAnalyser::passSpace()
{
    if (fgetc(_pFile) != ' ')
    {
        retractPointer();
    }
    else
    {
        while (fgetc(_pFile) == ' ');
        retractPointer();
    }
}
/*将当前读入的字符送入word数组中*/
void CTokenAnalyser::concatenation()
{
    _inputTokenBuffer[_wordNumber] = ch;
    _wordNumber++;
    _inputTokenBuffer[_wordNumber] = '\0';
}
/*判断是否是字母*/
int CTokenAnalyser::isLetter()
{
    if ((ch >='a'&&ch<='z')||(ch >='A'&&ch<='Z'))
        return 1;
    else
        return 0;
}
/*判断ch是否是数字*/
int CTokenAnalyser::isDigit()
{
    if (ch>='0'&&ch <='9')
        return 1;
    else
        return 0;
}
/*扫描指针回退一个字符*/
void CTokenAnalyser::retractPointer()
{
    fseek(_pFile,-1,SEEK_CUR);
}
/*判断是否是保留字。是则返回保留字对应的编码不是则返回标识符编码0*/
int CTokenAnalyser::isReserve()
{
    if (strcmp(_inputTokenBuffer,"auto") == 0)
        return 1;
    if (strcmp(_inputTokenBuffer,"break") == 0)
        return 2;
    if (strcmp(_inputTokenBuffer,"case") == 0)
        return 3;
    if (strcmp(_inputTokenBuffer,"char") == 0)
        return 4;
    if (strcmp(_inputTokenBuffer,"const") == 0)
        return 5;
    if (strcmp(_inputTokenBuffer,"continue") == 0)
        return 6;
    if (strcmp(_inputTokenBuffer,"default") == 0)
        return 7;
    if (strcmp(_inputTokenBuffer,"do") == 0)
        return 8;
    if (strcmp(_inputTokenBuffer,"double") == 0)
        return 9;
    if (strcmp(_inputTokenBuffer,"else") == 0)
        return 10;
    if (strcmp(_inputTokenBuffer,"enum") == 0)
        return 11;
    if (strcmp(_inputTokenBuffer,"extern") == 0)
        return 12;
    if (strcmp(_inputTokenBuffer,"float") == 0)
        return 13;
    if (strcmp(_inputTokenBuffer,"for") == 0)
        return 14;
    if (strcmp(_inputTokenBuffer,"goto") == 0)
        return 15;
    if (strcmp(_inputTokenBuffer,"if") == 0)
        return 16;
    if (strcmp(_inputTokenBuffer,"int") == 0)
        return 17;
    if (strcmp(_inputTokenBuffer,"long") == 0)
        return 18;
    if (strcmp(_inputTokenBuffer,"register") == 0)
        return 19;
    if (strcmp(_inputTokenBuffer,"return") == 0)
        return 20;
    if (strcmp(_inputTokenBuffer,"short") == 0)
        return 21;
    if (strcmp(_inputTokenBuffer,"signed") == 0)
        return 22;
    if (strcmp(_inputTokenBuffer,"sizeof") == 0)
        return 23;
    if (strcmp(_inputTokenBuffer,"static") == 0)
        return 24;
    if (strcmp(_inputTokenBuffer,"struct") == 0)
        return 25;
    if (strcmp(_inputTokenBuffer,"switch") == 0)
        return 26;
    if (strcmp(_inputTokenBuffer,"typedef") == 0)
        return 27;
    if (strcmp(_inputTokenBuffer,"union") == 0)
        return 28;
    if (strcmp(_inputTokenBuffer,"unsigned") == 0)
        return 29;
    if (strcmp(_inputTokenBuffer,"void") == 0)
        return 30;
    if (strcmp(_inputTokenBuffer,"volatile") == 0)
        return 31;
    if (strcmp(_inputTokenBuffer,"while") == 0)
        return 32;
    return 0;
}
/*将标识符登记到符号表中*/
void CTokenAnalyser::createIDList()
{
    int CTokenAnalyser::num;
    char bijiao[BUFFER_MAX_SIZE];
    _pIDFile =fopen("id_word.txt","r");
    /*查看符号是否已经存在*/
    while (fscanf(_pIDFile,"%d%s",&num,bijiao) != EOF)
    {
        if (strcmp(bijiao,_inputTokenBuffer) == 0)
        {
            fclose(_pIDFile);
            return ;
        }
    }
    fclose(_pIDFile);
    _pIDFile =fopen("id_word.txt","a");
    _idCounter++;
    fprintf(_pIDFile,"%d %s\n",_idCounter,_inputTokenBuffer);
    fclose(_pIDFile);
}
void CTokenAnalyser::createConstNumLIst()
{
    int CTokenAnalyser::num;
    char bijiao[BUFFER_MAX_SIZE];
    _pNumFile =fopen("num_word.txt","r");
    /*查看符号是否已经存在*/
    while (fscanf(_pIDFile,"%d%s",&num,bijiao) != EOF)
    {
        if (strcmp(bijiao,_inputTokenBuffer) == 0)
        {
            fclose(_pNumFile);
            return ;
        }
    }
    fclose(_pNumFile);
    _pNumFile =fopen("num_word.txt","a");
    _numCounter++;
    fprintf(_pNumFile,"%d %s\n",_numCounter,_inputTokenBuffer);
    fclose(_pNumFile);
}

void CTokenAnalyser::errorHandler()
{
    fprintf(_pCWordFile,"Error in the %d line!Unidentified token!\n",_lineNumber);
}

void CTokenAnalyser::getFileToAnalyse()
{
    char fileName[2048];


    printf("请输入待分析文件路径(小于2048个字符):\n");
    scanf("%s",fileName);

    _pFile = fopen(fileName,"r");
    _pCWordFile = fopen("cWords.txt","w");
    _pIDFile = fopen("id_word.txt","w");
    fclose(_pIDFile);
    _pNumFile = fopen("num_word.txt","w");
    fclose(_pNumFile);
    if (_pCWordFile == NULL||_pIDFile == NULL||_pNumFile == NULL)
    {
        printf("Fail to open the files to log results.");
        return ;
    }
    if (_pFile == NULL)
    {
        printf("Fail to open the input file[%s].", fileName);
        return ;
    }
}

void CTokenAnalyser::start()
{
    printf("------------C语言词法分析器------------\n");
    printf("---------Lex Analyser For C---------\n");

    getFileToAnalyse();

    analyse();

    outputResult();


    closeFiles();

}

int CTokenAnalyser::analyse()
{
    while (_isAnalyseComplete == 0&&(ch = fgetc(_pFile)) != EOF)
    {
        _wordNumber = 0;
        /*去除后面的空格符*/
        if (ch == '\t'||ch == ' ')
            continue;
        if (ch == '\n')
        {
            _lineNumber ++;
            continue;
        }
        /*标识符或保留字*/
        if ((ch >='a'&&ch<='z')||(ch >='A'&&ch<='Z'))
        {
            while (isLetter()||isDigit())
            {
                /*将当前读入的字符送入word数组中*/
                concatenation();
                if (_isAnalyseComplete == 0&&(ch = fgetc(_pFile)) == EOF)
                {
                    _isAnalyseComplete = 1;
                    break;
                }
            }
            retractPointer();/*扫描指针回退一个字符*/
            /*判断是否是保留字。是则返回保留字对应的编码*/
            _reverseWordCode = isReserve() - 1;
            if (_reverseWordCode == -1)
            {
                createIDList();/*将标识符添加到符号表中*/
                fprintf(wfp,"%s\t%s\n","ID",_inputTokenBuffer);
            }
            else
            {
                _reverseWordCounter++;
                fprintf(wfp,"%s\t%s\n","Reserve_word",_inputTokenBuffer);
            }
            passSpace();
            continue;
        }
        if (isDigit())
        {
            while (isDigit())
            {
                concatenation();
                if (_isAnalyseComplete == 0&&(ch = fgetc(_pFile)) == EOF)
                {
                    retractPointer();
                    break;
                }
            }
            if (isLetter())
            {
                fprintf(wfp,"Error!There exists a wrong ID in the %d line!",_lineNumber);
                while (isLetter())
                {
                    concatenation();
                    if (_isAnalyseComplete == 0&&(ch = fgetc(_pFile)) == EOF)
                    {
                        retractPointer();
                        break;
                    }
                }
                fprintf(wfp,"\t%s\n",_inputTokenBuffer);
                retractPointer();
                continue;
            }
            retractPointer();
            fprintf(wfp,"%s\t%s\n","num",_inputTokenBuffer);
            createConstNumLIst();
            passSpace();
            continue;
        }
        switch (ch)     /*处理标点符号及特殊符号*/
        {
        case '+':
            if (fgetc(_pFile) == '+')
            {
                fprintf(wfp,"%s\t%s\t%s\n","operation","add_one","++");
                break;
            }
            else
            {
                fprintf(wfp,"%s\t%s\t%s\n","operation","add","+");
                retractPointer();
                break;
            }
        case '-':
            if (fgetc(_pFile) == '-')
            {
                fprintf(wfp,"%s\t%s\t%s\n","operation","sub_one","--");
                break;
            }
            else
            {
                fprintf(wfp,"%s\t%s\t%s\n","operation","sub","-");
                retractPointer();
                break;
            }
        case '*':
            fprintf(wfp,"%s\t%s\n","special_symbol","*");
            break;
        case '<':
            if (fgetc(_pFile) == '=')
            {
                fprintf(wfp,"%s\t%s\t%s\n","relop","LE","<=");
                break;
            }
            else
            {
                fprintf(wfp,"%s\t%s\t%s\n","relop","LT","<");
                retractPointer();
                break;
            }
        case '=':
            if (fgetc(_pFile) == '=')
            {
                fprintf(wfp,"%s\t%s\t%s\n","relop","EQ","==");
                break;
            }
            else
            {
                fprintf(wfp,"%s\t%s\n","assign-op","=");
                retractPointer();
                break;
            }
        case '>':
            if (fgetc(_pFile) == '=')
            {
                fprintf(wfp,"%s\t%s\t%s\n","relop","GE",">=");
                break;
            }
            else
            {
                fprintf(wfp,"%s\t%s\t%s\n","relop","GT",">");
                retractPointer();
                break;
            }
        case ':':
            fprintf(wfp,"%s\t%s\n","special_symbol",":");
            break;
        case ';':
            fprintf(wfp,"%s\t%s\n","special_symbol",";");
            break;
        case '(':
            fprintf(wfp,"%s\t%s\n","special_symbol","(");
            break;
        case ')':
            fprintf(wfp,"%s\t%s\n","special_symbol",")");
            break;
        case '/':
            if (fgetc(_pFile) == '*')
            {
                while (fgetc(_pFile) != '*')
                    fgetc(_pFile);
                if (fgetc(_pFile) == '/')
                    break;
            }
            else
            {
                fprintf(wfp,"%s\t%s\t%s\n","operation","divide","/");
                retractPointer();
                break;
            }
        case '%':
             fprintf(wfp,"%s\t%s\n","special_symbol","%");
             break;
        case '#':
             fprintf(wfp,"%s\t%s\n","special_symbol","#");
             break;
        case '&':
            if (fgetc(_pFile) == '&')
            {
                fprintf(wfp,"%s\t%s\t%s\n","logic","AND","&&");
                break;
            }
            else
            {
                fprintf(wfp,"%s\t%s\n","special_symbol","&");
                retractPointer();
                break;
            }
        case '|':
            if (fgetc(_pFile) == '|')
            {
                fprintf(wfp,"%s\t%s\t%s\n","logic","OR","||");
                break;
            }
            else
            {
                fprintf(wfp,"%s\t%s\n","special_symbol","|");
                retractPointer();
                break;
            }
        case '!':
            if (fgetc(_pFile) == '=')
            {
                fprintf(wfp,"%s\t%s\t%s\n","relop","NE","!=");
                break;
            }
            else
            {
                fprintf(wfp,"%s\t%s\t%s\n","logic","NOT","!");
                retractPointer();
                break;
            }
        case '"':
             fprintf(wfp,"%s\n","special_symbol");
             break;
        case ',':
             fprintf(wfp,"%s\t%s\n","special_symbol",",");
             break;
        case '.':
             fprintf(wfp,"%s\t%s\n","special_symbol",".");
             break;
        case '{':
             fprintf(wfp,"%s\t%s\n","special_symbol","{");
             break;
        case '}':
             fprintf(wfp,"%s\t%s\n","special_symbol","}");
             break;
        case '[':
             fprintf(wfp,"%s\t%s\n","special_symbol","[");
             break;
        case ']':
             fprintf(wfp,"%s\t%s\n","special_symbol","]");
             break;
        case '?':
             fprintf(wfp,"%s\t%s\n","special_symbol","?");
             break;
        case '^':
             fprintf(wfp,"%s\t%s\n","special_symbol","^");
             break;
        case '_':
             fprintf(wfp,"%s\t%s\n","special_symbol","_");
             break;
        default:
            errorHandler();
        }
        passSpace();
    }
}

void CTokenAnalyser::closeFiles()
{
    fclose(numfp);
    fclose(wfp);
    fclose(_pFile);
}

void CTokenAnalyser::outputResult()
{
    printf("分析完毕!\n"
           "共%d行.\n"
           "标识符数量为%d,\n”
           "详细信息如下(也可参看日志文件):",
           _lineNumber,_idCounter);

}




